#include <stdio.h>
#include <stdlib.h>
#include <asm/ptrace.h>
#include <asm/user.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <utils/Log.h>


#define ENABLE_DEBUG 	1

#define PTRACE_PEEKTEXT	1
#define PTRACE_POKETEXT 4
#define PTRACE_ATTACH	16
#define PTRACE_CONT		7
#define PTRACE_DETACH	17
#define PTRACE_SYSCALL	24
#define CPSR_T_MASK		(1u << 5)

#define MAX_PATH		0x100

#define REMOTE_ADDR(addr, local_base, remote_base)	((uint32_t)(addr) + (uint32_t)(remote_base) - (uint32_t)(local_base))


const char *libc_path = "/system/lib/libc.so"
const char *linker_path = "/system/bin/linker";


#if ENABLE_DEBUG
	#define DEBUG_PRINT(format, args...)\
		LOGD(format, ##args)
#else
	#define DEBUG_PRINT(format, args...)
#endif


/*
 * 从目标进程指定位置读取数据
 */
int ptrace_readdata(pid_t pid, uint8_t *src, uint8_t *buf, size_t size)
{
	uint32_t i, j, remain;
	uint8_t *laddr;

	union u {
		long val;
		char chars[sizeof(long)]''
	} d;

	j = size / 4;
	remain = size & 4;

	laddr = buf;

	for (i = 0; i < j; ++i)
	{
		// 一次读取 4 个字节
		d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
		memcpy(laddr, d.chars, 4);
		src += 4;
		laddr += 4;
	}

	// 处理剩下的不足 4 个字节
	if (remain > 0)
	{
		d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
		memcpy(laddr, d.chars, remain);
	}
	return 0;
}


/*
 * 向目标进程指定位置写入数据
 */
int ptrace_writedata(pid_t pid, uint8_t *dest, uint8_t *data, size_t size)
{
	uint32_t i, j, remain;
	uint8_t *laddr;

	union u {
		long val;
		char chars[sizeof(long)];
	} d;

	j = size / 4;
	remain = size % 4;

	laddr = data;

	for (i = 0; i < j; ++i)
	{
		// 一次写入 4 个字节
		memcpy(d.chars, laddr, 4);
		ptrace(PTRACE_POKETEXT, pid, dest, d.val);

		dest += 4;
		laddr += 4;
	}

	// 处理剩下的不足 4 个字节
	if (remain > 0)
	{
		d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0);
		for ( i = 0; i < remain; ++i)
		{
			d.chars[i] = *laddr ++;
		}
		ptrace(PTRACE_POKETEXT, pid, dest, d.val);
	}
	return 0;
}


int ptrace_writestring(pid_t pid, uint8_t *dest, char *str)
{
	return ptrace_writedata(pid, dest, str, strlen(str)+1);
}


/*
 * 获取通用寄存器的值
 */
 int ptrace_getregs(pid_t pid, struct pt_regs* regs)
 {
 	if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0)
 	{
 		perror("ptrace_getregs：Can not get register values");
 		return -1;
 	}

 	return 0;
 }


/*
 * 设置通用寄存器的值
 */ 
int ptrace_setregs(pid_t pid, struct pt_regs* regs)
{
	if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0)
	{
		perror("ptrace_setregs：Can not set register values");
		return -1;
	}

	return 0;
}


/*
 * 附加一个进程
 */
 int ptrace_attch(pid_t pid)
 {
 	if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0)
 	{
 		perror("ptrace_attach");
 		return -1;
 	}

 	waitpid(pid, NULL, WUNTRACED);

 	if (ptrace(PTRACE_SYSCALL, pid, NULL, 0) < 0)
 	{
 		perror("ptrace_syscall");
 		return -1;
 	}

 	waitpid(pid, NULL, WUNTRACED);
 	return 0;
 }


/*
 * 分离附加的进程
 */
 int ptrace_detach(pid_t pid)
 {
 	if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0)
 	{
 		perror("ptrace_detach");
 		return -1;
 	}
 	return 0;
 }


/*
 * 继续运行进程
 */
 int ptrace_continue(pid_t pid)
 {
 	if (ptrace(PTRACE_CONT, pid, NULL, 0) < 0)
 	{
 		perror("ptrace_cont");
 		return -1;
 	}
 	return 0;
 }


/*
 * 在目标进程中调用函数
 * pid：目标进程标识
 * addr：函数地址
 * params：参数
 * num_params：参数个数
 * regs：目标进程寄存器结构体
 */
int ptrace_call(pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs)
{
	uint32_t i;

	// 前四个参数通过 R0、R1、R2、R3 通用寄存器传递
	for (i = 0; i < num_params && i < 4; ++i)
	{
		regs->uregs[i] = params[i];
	}

	// 剩下的参数通过栈传递
	if (i < num_params)
	{
		// 分配栈空间
		regs->ARM_sp -= (num_params -i) * sizeof(long);
		// 将参数写入栈中
		ptrace_writedata(pid, (void *)regs->ARM_sp, (uint8_t *)&params[i], (num_params - i) * sizeof(long));
	}

	regs->ARM_pc = addr;
	if (regs->ARM_pc & 1)
	{
		/* thumb */

		// 修正函数的实际地址
		regs->ARM_pc &= (~1u);
		// 设置 T 标志位
		regs->ARM_cpsr |= CPSR_T_MASK;
	}
	else
	{
		/* arm */

		// 设置 T 标志位
		regs->ARM_cpsr &= ~CPSR_T_MASK;
	}

	// lr 设置为 0？？？？？
	regs->ARM_lr = 0;

	if ((ptrace_setregs(pid, regs) == -1) || (ptrace_continue(pid) == -1))
	{
		return -1;
	}

	// WUNTRACED 标志：若子进程进入暂停状态，则马上返回，但子进程的结束状态不予以理会。
	waitpid(pid, NULL, WUNTRACED);
	return 0;
}


/*
 * 获取模块的可执行模块基地址
 */
 void* get_module_base(pid_t pid, const char* module_name)
 {
 	FILE *fp;
 	long addr = 0;
 	char *pch;
 	char filename[32];
 	char line[1024];

 	if (pid < 0)
 	{
 		snprintf(filename, sizeof(filename), "/proc/self/maps");
 	}
 	else
 	{
 		snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
 	}

 	// 从 proc 读取进程信息
 	fp = fopen(filename, "r");
 	if (fp != NULL)
 	{
 		while (fgets(line, sizeof(line), fp))
 		{
 			if (strstr(line, module_name))
 			{
 				/*
 				 * 这里要注意，获取的是代码模块空间，也就是可读可执行模块
 				 * 进程 maps 文件里每个模块都有 3 个对应的记录
 				 * 依次是：可读可执行模块、可读模块、可读可写模块
 				 *
 				 * 这里获取的是第一个，也就是可读可执行模块  
 				 */
 				pch = strsep(line, "-");

 				addr = strtoul(pch, NULL, 16);
 				// 0x80000000-0xFFFFFFFF 是系统地址 空间
 				if (addr >= 0x80000000)
 				{
 					addr = 0;
 				}

 				break;
 			}
 		}
 		fclose(fp);
 	}
 	return (void *)addr;
 }


/*
 * 获取函数在目标进程中的地址
 */
void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr)
{
	void* local_handle;
	void* remote_handle;

	local_handle = get_module_base(getpid(), module_name);
	remote_handle = get_module_base(target_pid, module_name);

	DEBUG_PRINT("[+] get_remote_addr：local[%x], remote[%x]\n". local_handle, remote_handle);

	return (void *)((uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle);
}


// 根据进程绝对路径查找进程id
int find_pid_of(const char *process_name)
{
	int id;
	pid_t pid = -1;
	DIR *dir;
	FILE *fp;
	char filename[32];
	char cmdline[256];

	struct dirent *entry;

	if (process_name == NULL)
	{
		return -1;
	}

	dor = opendir("/proc");
	if (dir == NULL)
	{
		return -1;
	}

	while ((entry = readdir(dir)) != NULL)
	{
		id = atoi(entry->d_name);
		if (id != 0)
		{
			sprintf(filename, "/proc/%d/cmdline", id);
			fp = fopen(filename, "r");
			if (fp)
			{
				fgets(cmdline, sizeof(cmdline), fp);
				fclose(fp);

				if (strcmp(process_name, cmdline) == 0)
				{
					// proess found
					pid = id;
					break;
				}
			}
		}
	}
	closedir(dir);
	return pid;
}

int get_file_len(const char *file_name)
{
	FILE* fd;
	if ( (fd = open(file_name, "r")) < 0)
	{
		return 0;
	}

	struct stat file_stat;
	if ( fstat( fd, &file_stat) < 0 )
	{
		return 0;
	}

	fclose(fd);
	return file_stat.st_size;
}

int inject_remote_process(pid_t target_pid, const char *library_path, const char *function_name, void *param, size_t param_size)
{
	int ret = -1;
	void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr;
	void *local_handle, *remote_handle, *dlhandle;
	uint8_t *map_base;
	uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;

	struct pt_regs regs, original_regs;
	extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s,\
			_dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s,\
			_saved_cpsr_s, _saved_r0_pc_s;

	uint32_t code_length;

	long paramters[10];

	DEBUG_PRINT("[+] Injecting process：%d\n", target_pid);

	if (ptrace_attach(target_pid) == -1)
	{
		return ret;
	}

	if (ptrace_getregs(target_pid, &regs) == -1)
	{
		return ret;
	}

	// 保存原始寄存器
	memcpy(&original_regs, &regs, sizeof(regs));

	mmap_addr = get_remote_addr(target_pid, libc_path, (void *)mmap);
	DEBUG_PRINT("[+] Remote mmap address：%x\n", mmap_addr);


	// 调用 mmap
	parameters[0] = 0;		// addr
	parameters[1] = get_file_len(libc_path);	// length
	parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;		// prot
	parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE;		// flags
	parameters[4] = -1;		// fd
	parameters[5] = 0;		// offset

	DEBUG_PRINT("[+] Calling mmap in target process.\n");

	if (ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, &regs) == -1)
	{
		return ret;
	}

	if (ptrace_getregs(target_pid, &regs) == -1)
	{
		return -1;
	}

	DEBUG_PRINT("[+] Target process returned from mmap, return value=%x, pc=%x \n", regs.ARM_r0, regs.ARM_pc);			// 此处 PC 应该是 0？？？

	// 加载的基地址
	map_base = (uint8_t *)regs.ARM_r0;

	dlopen_addr = get_remote_addr(target_pid, linker_path, (void *)dlopen);
	dlsym_addr = get_remote_addr(target_pid, linker_path, (void *)dlsym);
	dlclose_addr = get_remote_addr(target_pid, linker_path, (void *)dlclose);

	DEBUG_PRINT("[+] Get imports：dlopen：%x，dlsym：%x，dlclose：%x\n", dlopen_addr, dlsym_addr, dlclose_addr);

	remote_code_ptr = map_base + 0x3C00;
	local_code_ptr = (uint8_t *)&_inject_start_s;

	_dlopen_addr_s = (uint32_t)dlopen_addr;
	_dlsym_addr_s = (uint32_t)dlsym_addr;
	_dlclose_addr_s = (uint32_t)dlclose_addr;

	DEBUG_PRINT("[+] Inject code start:%x, end:%x\n", local_code_ptr, &_inject_ends_s);

	code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;
	dlopen_param1_ptr = local_code_ptr + code_length + 0x20;
	dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;
	saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;
	inject_param_ptr = saved_r0_pc_ptr + MAX_PATH;

	strcpy(dlopen_param1_ptr, library_path);
	



}


int main(int argc, char** argv)
{
	pid_t target_pid;
	target_pid = find_pid_of("/system/bin/servicemanager");
	inject_remote_process(target_pid, "/dev/yuki/payload.so", "hook_entry", "I'm parameter!", strlen("I'm parameter!"));
}